// 新增: 引入 child_process 模块
const { spawn } = require('child_process');

// 新增: 引入 fs 模块
const fs = require('fs');

const AdmZip = require('adm-zip');

// 新增: 引入 path 模块
const path = require('path');

// 新增: 全局配置变量
let globalConfig = null;

// 新增: 初始化全局配置的方法
async function initGlobalConfig(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`Failed to fetch config: ${response.statusText} (Status Code: ${response.status})`);
        }
        globalConfig = await response.json();
        // 确保 hashcash 配置项存在，默认值为 false
        globalConfig.hashcash = globalConfig.hashcash ?? false;
        return globalConfig;
    } catch (error) {
        console.error('Error initializing global scoop config:', error.message);
        throw error;
    }
}

// 新增: 获取全局配置的方法
function getGlobalConfig() {
    if (!globalConfig) {
        throw new Error('Global config is not initialized. Please call initGlobalConfig first.');
    }
    return globalConfig;
}

// 新增: 检查仓库是否存在的方法
async function isRepoExists(repoPath) {
    try {
        const stats = await fs.promises.stat(repoPath);
        return stats.isDirectory();
    } catch (error) {
        return false;
    }
}

// 新增: 执行 Git 命令的方法
async function execGitCommand(cwd, command) {
    return new Promise((resolve, reject) => {
        console.log(`Executing git command in directory: ${cwd}`);
        console.log(`Command: git ${command}`);
        
        const gitProcess = spawn('D:\\env\\git\\2.49.0\\cmd\\git.exe', command.split(' '), { cwd });
        
        // 捕获标准输出
        gitProcess.stdout.on('data', (data) => {
            console.log(`stdout: ${data}`);
        });
        
        // 捕获标准错误输出
        gitProcess.stderr.on('data', (data) => {
            console.error(`stderr: ${data}`);
        });
        
        gitProcess.on('close', (code) => {
            if (code === 0) {
                console.log(`Git command completed successfully with code ${code}`);
                resolve();
            } else {
                console.error(`Git command failed with code ${code}`);
                reject(new Error(`Git command failed with code ${code}`));
            }
        });
        
        gitProcess.on('error', (error) => {
            console.error(`Git command execution error: ${error.message}`);
            reject(error);
        });
    });
}

// 新增: 封装的创建路径方法
async function mkDir(path) {
    try {
        await fs.promises.mkdir(path, { recursive: true });
        console.log(`Path created: ${path}`);
        return path;
    } catch (error) {
        console.error(`Failed to create path: ${path}`, error.message);
        throw error;
    }
}

// 新增: 读取 bucket 文件夹中的 JSON 文件并解析为对象，并包含文件路径
async function loadSoftwareConfigs(bucketPath) {
    try {
        const files = await fs.promises.readdir(bucketPath);
        const softwareConfigs = {};

        for (const file of files) {
            if (file.endsWith('.json')) {
                const filePath = `${bucketPath}/${file}`;
                const content = await fs.promises.readFile(filePath, 'utf-8');
                const config = JSON.parse(content);
                const name = file.replace('.json', '');
                softwareConfigs[name] = {
                    ...config,
                    filePath // 添加文件路径信息
                };
            }
        }

        return softwareConfigs;
    } catch (error) {
        console.error('Error loading software configs:', error.message);
        throw error;
    }
}

// 新增: 全局变量存储软件配置
let softwareConfigs = {};

// 新增: 下载文件的方法
async function downloadFile(url, destination) {
    try {
        // 检查文件是否已经存在
        try {
            await fs.promises.access(destination);
            console.log(`File already exists, skipping download: ${destination}`);
            return;
        } catch (error) {
            // 文件不存在，继续下载流程
        }

        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`Failed to download file: ${response.statusText} (Status Code: ${response.status})`);
        }

        // 使用 pipeline 处理流式数据
        const { pipeline } = require('stream');
        const { promisify } = require('util');
        const finished = promisify(require('stream').finished);

        const fileStream = fs.createWriteStream(destination);
        await pipeline(response.body, fileStream, (err) => {
            if (err) {
                console.error('Pipeline error:', err);
                throw err;
            }
        });
        await finished(fileStream); // 确保流完成

        console.log(`File downloaded successfully: ${destination}`);
    } catch (error) {
        console.error('Error downloading file:', error.message);
        throw error;
    }
}

// 新增: 解压 ZIP 文件的方法
function extractZipFile(zipFilePath, targetPath) {
    try {
        const zip = new AdmZip(zipFilePath);
        const entries = zip.getEntries();

        for (const entry of entries) {
            const entryPath = entry.entryName.replace(/^[^/]+\//, '');
            const fullPath = path.join(targetPath, entryPath); // 使用 path 模块拼接路径

            try {
                // 确保目录存在
                const dirPath = path.dirname(fullPath);
                if (!fs.existsSync(dirPath)) {
                    fs.mkdirSync(dirPath, { recursive: true });
                }

                // 如果是文件，则写入文件
                if (!entry.isDirectory) {
                    fs.writeFileSync(fullPath, entry.getData(), 'binary');
                }
            } catch (error) {
                console.error(`Error extracting file ${entryPath}: ${error.message}`);
                // 继续解压下一个文件
            }
        }
    } catch (error) {
        console.error(`Error extracting zip file: ${error.message}`);
        throw new Error(`Failed to extract zip file: ${error.message}`);
    }
}

// 新增: 安装软件的方法
async function installSoftware(softwareName) {
    try {
        const [name, version] = softwareName.split('@');
        const config = softwareConfigs[name];
        if (!config) {
            throw new Error(`Software configuration not found for ${name}`);
        }

        // 处理依赖项
        if (config.depends && config.depends.length > 0) {
            console.log(`Processing dependencies for ${name}`);
            for (const dependency of config.depends) {
                const [depName, depVersion] = dependency.split('@');
                const depSoftwareName = depVersion ? `${depName}:${depVersion}` : depName;
                await installSoftware(depSoftwareName);
            }
        }

        const { architecture, extract_dir, env_add_path, pre_install, installer, post_install } = config;
        const { url, hash } = architecture['64bit']; // 假设默认为 64 位架构

        // 获取全局配置中的 root 和 cache_path 路径
        const globalConfig = getGlobalConfig();
        const rootPath = globalConfig.root;
        const cachePath = globalConfig.cache_path;

        // 动态获取文件扩展名并构造 downloadPath
        const urlParts = url.split('/');
        const fileName = urlParts[urlParts.length - 1];
        const fileExtension = path.extname(fileName);
        // 动态处理版本号，避免拼接 undefined
        const downloadPath = version 
            ? `${cachePath}/${name}-${version}${fileExtension}`
            : `${cachePath}/${name}${fileExtension}`;

        // 构造解压路径
        const extractPath = `${rootPath}/${extract_dir}`;

        // 下载文件
        await downloadFile(url, downloadPath);

        // 如果 hashcash 为 true，则校验文件哈希
        if (globalConfig.hashcash) {
            // 校验逻辑待实现
        }

        // 如果解压路径不为空，才执行解压操作
        if (extract_dir) {
            // 确保解压路径存在
            await mkDir(extractPath);

            // 判断是否为压缩包
            const supportedArchives = ['.zip', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2', '.tar.xz', '.txz', '.7z', '.rar'];
            const isArchive = supportedArchives.some(ext => downloadPath.endsWith(ext)); // 使用 downloadPath 判断是否为压缩包

            if (isArchive) {
                // 检查解压路径是否已存在
                if (await isRepoExists(extractPath)) {
                    console.log(`Extracted path already exists, skipping extraction: ${extractPath}`);
                } else {
                    console.log(`Extracting archive: ${downloadPath} to ${extractPath}`);
                    await extractZipFile(downloadPath, extractPath);
                }
            } else {
                const targetFilePath = `${extractPath}/${path.basename(downloadPath)}`;
                fs.copyFileSync(downloadPath, targetFilePath);
                console.log(`Copied file to ${targetFilePath}`);
            }
        }

        // 执行 pre_install 脚本（如果存在）
        if (pre_install) {
            console.log(`Executing pre_install scripts for ${name}:${version}`);
            await executeScripts(pre_install, extractPath);
        }

        // 添加 bin 到 PATH
        if (config.bin) {
            const binPaths = Array.isArray(config.bin) ? config.bin : [config.bin];
            for (const bin of binPaths) {
                const binPath = path.join(extractPath, bin);
                if (fs.existsSync(binPath)) {
                    createShortcut(binPath,null);
                    console.log(`Created shortcut for ${name}`);
                } else {
                    console.warn(`Target file not found for shortcut: ${targetPath}`);
                }
            }
        }

        // 创建快捷方式
        if (config.shortcuts) {
            const shortcuts = Array.isArray(config.shortcuts) ? config.shortcuts : [config.shortcuts];
            for (const shortcut of shortcuts) {
                const [target, name] = shortcut;
                const targetPath = path.join(extractPath, target);
                if (fs.existsSync(targetPath)) {
                    createShortcut(targetPath, name);
                    console.log(`Created shortcut for ${name}`);
                } else {
                    console.warn(`Target file not found for shortcut: ${targetPath}`);
                }
            }
        }

        // 执行 installer 脚本（如果存在）
        if (installer) {
            console.log(`Executing installer scripts for ${name}:${version}`);
            await executeScripts(installer, extractPath);
        }

        // 添加环境变量
        if (env_add_path) {
            const envPath = `${extractPath}/${env_add_path}`;
            console.log(`Added ${envPath} to PATH`);
            addToPath(envPath);
        }

        // 执行 post_install 脚本（如果存在）
        if (post_install) {
            console.log(`Executing post_install scripts for ${name}:${version}`);
            await executeScripts(post_install, extractPath);
        }

        console.log(`Software ${name}:${version} installed successfully.`);
    } catch (error) {
        console.error(`Error installing software ${softwareName}:`, error.message);
        throw error;
    }
}

// 新增: 执行脚本的方法
async function executeScripts(scripts, workingDirectory) {
    if (!scripts) return;

    const scriptArray = Array.isArray(scripts) ? scripts : [scripts];
    
    // 统一生成 .ps1 文件
    const globalConfig = getGlobalConfig();
    const scriptDir = `${globalConfig.cache_path}/script`;
    const scriptFileName = `temp_script_${Date.now()}.ps1`;
    const scriptFilePath = `${scriptDir}/${scriptFileName}`;

    // 确保 script 目录存在
    await mkDir(scriptDir);

    // 将脚本内容写入 .ps1 文件
    const scriptContent = scriptArray.join('\n');
    await fs.promises.writeFile(scriptFilePath, scriptContent, 'utf-8');

    console.log(`Created temporary script file: ${scriptFilePath}`);

    // 使用 PowerShell 执行 .ps1 文件
    try {
        console.log(`Running script file: ${scriptFilePath}`);
        const psProcess = spawn('powershell.exe', ['-File', scriptFilePath], { cwd: workingDirectory });
        
        psProcess.stdout.on('data', (data) => {
            console.log(`Script stdout: ${data}`);
        });

        psProcess.stderr.on('data', (data) => {
            console.error(`Script stderr: ${data}`);
        });

        await new Promise((resolve, reject) => {
            psProcess.on('close', (code) => {
                if (code === 0) {
                    console.log(`Script completed successfully with code ${code}`);
                    resolve();
                } else {
                    console.error(`Script failed with code ${code}`);
                    reject(new Error(`Script failed with code ${code}`));
                }
            });

            psProcess.on('error', (error) => {
                console.error(`Script execution error: ${error.message}`);
                reject(error);
            });
        });

        // 执行完成后删除临时脚本文件
        await fs.promises.unlink(scriptFilePath);
        console.log(`Deleted temporary script file: ${scriptFilePath}`);
    } catch (error) {
        console.error(`Error executing script file: ${scriptFilePath}`, error.message);
        throw error;
    }
}

// 新增: 执行 cmd 命令的公用方法
function executeCmdCommand(command) {
    return new Promise((resolve, reject) => {
        console.log(`Executing cmd command: ${command}`); // 确保日志输出

        // 修改: 修正 spawn 参数传递方式
        const cmdProcess = spawn('cmd.exe', ['/s', '/c', `chcp 65001 >nul && ${command}`]);

        // 捕获标准输出并打印详细日志
        cmdProcess.stdout.on('data', (data) => {
            console.log(`Cmd stdout: ${data.toString().trim()}`); // 转换为字符串并去除多余空格
        });

        // 捕获标准错误输出并打印详细日志
        cmdProcess.stderr.on('data', (data) => {
            console.error(`Cmd stderr: ${data.toString().trim()}`); // 转换为字符串并去除多余空格
        });

        cmdProcess.on('close', (code) => {
            if (code === 0) {
                console.log(`Cmd command completed successfully with code ${code}`);
                resolve();
            } else {
                console.error(`Cmd command failed with code ${code}`);
                reject(new Error(`Cmd command failed with code ${code}`));
            }
        });

        cmdProcess.on('error', (error) => {
            console.error(`Cmd command execution error: ${error.message}`);
            reject(error);
        });
    });
}

//工具函数，将路径转换为 Windows 格式
function toWindowsPath(str) {
    // 只替换引号内的路径 或 独立路径格式的字符串（如 C:/xxx）
    return str.replace(/("[^"]+")|([a-zA-Z]:[/\\][^"\s]+)/g, (match, quotedPath, rawPath) => {
        if (quotedPath) {
            const winPath = quotedPath.slice(1, -1);
            return `"${winPath.replace(/\//g, '\\')}"`;
        } else if (rawPath) {
            return rawPath.replace(/\//g, '\\');
        }
        return match;
    });
}

// 修改: 添加路径到环境变量的方法
function addToPath(newPath) {
    let windowsPath = toWindowsPath(newPath);
    const setxCommand = `setx /M PATH "%PATH%;${windowsPath}"`;
    executeCmdCommand(setxCommand); // 调用公用方法执行 cmd 命令
    console.log(`Added ${newPath} to PATH`);
}

// 新增: 创建快捷方式的方法
function createShortcut(targetPath, shortcutName) {
    const globalConfig = getGlobalConfig();
    // 如果 shortcutName 为空，使用 targetPath 的文件名作为快捷方式名称
    if (!shortcutName) {
        shortcutName = path.basename(targetPath, path.extname(targetPath));
    }
    const shortcutPath = path.join(globalConfig.bin, `${shortcutName}.lnk`);
    const shell = require('node-powershell');
    const ps = new shell({
        executionPolicy: 'Bypass',
        noProfile: true
    });

    ps.addCommand(`$WshShell = New-Object -comObject WScript.Shell`);
    ps.addCommand(`$Shortcut = $WshShell.CreateShortcut("${shortcutPath}")`);
    ps.addCommand(`$Shortcut.TargetPath = "${targetPath}"`);
    ps.addCommand(`$Shortcut.Save()`);

    ps.invoke().then(output => {
        console.log(`Shortcut created: ${shortcutPath}`);
    }).catch(err => {
        console.error(`Error creating shortcut: ${err}`);
    });
}

// 新增: 添加 bin 路径到环境变量的方法
function addToEnv() {
    const globalConfig = getGlobalConfig();
    addToPath(globalConfig.bin);
    console.log(`Added ${globalConfig.bin} to PATH`);
}

// 修改: 处理 bucket 的方法，添加软件配置加载
async function getBucket() {
    const config = getGlobalConfig();
    const { bucket, cache_path } = config;

    // 确保 cache_path 存在
    await mkDir(cache_path);

    for (const item of bucket) {
        const { name, url } = item;
        const repoPath = `${cache_path}/${name}`;
        try {
            // 检查仓库是否存在
            if (await isRepoExists(repoPath)) {
                // 如果存在，执行 git pull
                await execGitCommand(repoPath, 'pull');
                console.log(`Updated bucket ${name} from ${url}`);

                // 加载软件配置
                const bucketPath = `${repoPath}/bucket`;
                softwareConfigs = { ...softwareConfigs, ...(await loadSoftwareConfigs(bucketPath)) };
            } else {
                // 如果不存在，执行 git clone
                await execGitCommand(cache_path, `clone ${url} ${name}`);
                console.log(`Cloned bucket ${name} from ${url}`);

                // 加载软件配置
                const bucketPath = `${repoPath}/bucket`;
                softwareConfigs = { ...softwareConfigs, ...(await loadSoftwareConfigs(bucketPath)) };
            }
        } catch (error) {
            console.error(`Error processing bucket ${name}:`, error.message);
        }
    }
}


// 修改: main 方法，添加将 globalConfig.bin 加入环境的步骤
async function main() {
    const configUrl = 'https://gitee.com/luckylqm/config/raw/master/scoop.json';
    try {
        await initGlobalConfig(configUrl);
        console.log('Global Config Initialized:', getGlobalConfig());
        await getBucket();
        console.log('All buckets processed successfully.');

        // 将 globalConfig.bin 加入环境变量
        // addToEnv(globalConfig.bin);

        // 输出软件配置
        // const formattedConfigs = Object.entries(softwareConfigs)
        //     .map(([name, config]) => `${name}:${config.version} (Path: ${config.filePath})`)
        //     .join('\n');
        // console.log('Loaded Software Configs:');
        // console.log(formattedConfigs);

        // 安装指定软件
        // await installSoftware('corretto8-jdk@8.452.09.1');
        await installSoftware('corretto8-jdk');

    } catch (error) {
        console.error('Failed to process buckets:', error.message);
    }
}

// 调用 main 方法
main();
